﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using DynORM.Interfaces;
using DynORM.ValueObjects;

namespace DynORM.ReferenceObjects
{

    public static class AuxRelation
    {
        public static IRelation ChangeFieldInRelation(IRelation oldRelation, IFieldDescriptor oldFieldDescriptor, object newFieldValue)
        {
            KeyValuePair<int, IField> oldFkv = oldRelation.Fields.First<KeyValuePair<int, IField>>(kv => kv.Value.GetDescriptor().Equals(oldFieldDescriptor));
            IField newF = new Field((FieldDescriptor)oldFkv.Value.GetDescriptor(), newFieldValue);
            Dictionary<int, IField> newFields = new Dictionary<int, IField>();
            newFields.Add(oldFkv.Key, newF);
            foreach (KeyValuePair<int, IField> fkv in oldRelation.Fields.Where<KeyValuePair<int, IField>>(kv => !kv.Value.GetDescriptor().Equals(oldFieldDescriptor)))
                newFields.Add(fkv.Key, fkv.Value);

            IRelation newR;
            if (oldRelation.RelationType == RelationType.PrimaryKey)
                newR = new PrimaryKey(oldRelation.TableName, newFields, oldRelation.Name);
            else if (oldRelation.RelationType == RelationType.ForeignKey)
                newR = new ForeignKey(oldRelation.TableName, newFields, ((IForeignKey)oldRelation).RelatedTableName, ((IForeignKey)oldRelation).RelatedFields, oldRelation.Name);
            else
                throw new Exception("Relation type is not supported.");

            return newR;
        }

        public static IPrimaryKeyDescriptor ChangeFieldDescInRelationDesc(IPrimaryKeyDescriptor oldRelationDescriptor, IFieldDescriptor oldFieldDescriptor, IFieldDescriptor newFieldDescriptor)
        {
            KeyValuePair<int, IFieldDescriptor> oldFDkv = oldRelationDescriptor.FieldDescriptors.First<KeyValuePair<int,IFieldDescriptor>>(fdkv => fdkv.Value.Equals(oldFieldDescriptor));
            int order = oldFDkv.Key;
            IDictionary<int, IFieldDescriptor> newFieldDescs = new Dictionary<int, IFieldDescriptor>();
            foreach (KeyValuePair<int, IFieldDescriptor> fd in oldRelationDescriptor.FieldDescriptors.Where<KeyValuePair<int, IFieldDescriptor>>(fdkv => !fdkv.Value.Equals(oldFieldDescriptor)))
                newFieldDescs.Add(fd.Key, fd.Value);
            newFieldDescs.Add(order, newFieldDescriptor);

            return new PrimaryKeyDescriptor(oldRelationDescriptor.TableName, newFieldDescs, oldRelationDescriptor.Name);
        }

        public static IForeignKeyDescriptor ChangeFieldDescInRelationDesc(IForeignKeyDescriptor oldRelationDescriptor, IFieldDescriptor oldFieldDescriptor, IFieldDescriptor newFieldDescriptor)
        {
            KeyValuePair<int, IFieldDescriptor> oldFDkv = oldRelationDescriptor.FieldDescriptors.First<KeyValuePair<int, IFieldDescriptor>>(fd => fd.Value.Equals(oldFieldDescriptor));
            Dictionary<int, IFieldDescriptor> newFieldDescs = new Dictionary<int, IFieldDescriptor>();
            newFieldDescs.Add(oldFDkv.Key, newFieldDescriptor);
            foreach (KeyValuePair<int, IFieldDescriptor> kv in oldRelationDescriptor.FieldDescriptors.Where<KeyValuePair<int, IFieldDescriptor>>(kv => !kv.Value.Equals(oldFieldDescriptor)))
                newFieldDescs.Add(kv.Key, kv.Value);

            return new ForeignKeyDescriptor(oldRelationDescriptor.TableName, newFieldDescs, ((IForeignKeyDescriptor)oldRelationDescriptor).RelatedTableName, ((IForeignKeyDescriptor)oldRelationDescriptor).RelatedFieldDescriptors, oldRelationDescriptor.Name);
        }

        public static IPrimaryKeyDescriptor ChangeFieldDescInRelationDesc(IPrimaryKeyDescriptor oldRelationDescriptor, IFieldDescriptor oldFieldDescriptor, string newFieldName)
        {
            KeyValuePair<int, IFieldDescriptor> oldFDkv = oldRelationDescriptor.FieldDescriptors.First<KeyValuePair<int, IFieldDescriptor>>(kv => kv.Value.Equals(oldFieldDescriptor));
            IFieldDescriptor newFD = new FieldDescriptor(oldFDkv.Value.FieldType, newFieldName);
            Dictionary<int, IFieldDescriptor> newFieldDescs = new Dictionary<int, IFieldDescriptor>();
            newFieldDescs.Add(oldFDkv.Key, newFD);
            foreach (KeyValuePair<int, IFieldDescriptor> kv in oldRelationDescriptor.FieldDescriptors.Where<KeyValuePair<int, IFieldDescriptor>>(kv => !kv.Value.Equals(oldFieldDescriptor)))
                newFieldDescs.Add(kv.Key, kv.Value);

            return new PrimaryKeyDescriptor(oldRelationDescriptor.TableName, newFieldDescs, oldRelationDescriptor.Name);
        }

        public static IForeignKeyDescriptor ChangeFieldDescInRelationDesc(IForeignKeyDescriptor oldRelationDescriptor, IFieldDescriptor oldFieldDescriptor, string newFieldName)
        {
            KeyValuePair<int, IFieldDescriptor> oldFDkv = oldRelationDescriptor.FieldDescriptors.First<KeyValuePair<int, IFieldDescriptor>>(kv => kv.Equals(oldFieldDescriptor));
            IFieldDescriptor newFD = new FieldDescriptor(oldFDkv.Value.FieldType, newFieldName);
            Dictionary<int, IFieldDescriptor> newFieldDescs = new Dictionary<int, IFieldDescriptor>();
            newFieldDescs.Add(oldFDkv.Key, newFD);
            foreach (KeyValuePair<int, IFieldDescriptor> kv in oldRelationDescriptor.FieldDescriptors.Where<KeyValuePair<int, IFieldDescriptor>>(kv => !kv.Value.Equals(oldFieldDescriptor)))
                newFieldDescs.Add(kv.Key, kv.Value);

            return new ForeignKeyDescriptor(oldRelationDescriptor.TableName, newFieldDescs, ((IForeignKeyDescriptor)oldRelationDescriptor).RelatedTableName, ((IForeignKeyDescriptor)oldRelationDescriptor).RelatedFieldDescriptors, oldRelationDescriptor.Name);
        }

        public static IRelationDescriptor ChangeRelationDescName(IRelationDescriptor relationDescriptor, string newName)
        {
            IRelationDescriptor result;
            if (relationDescriptor.RelationType == RelationType.PrimaryKey)
                result = new PrimaryKeyDescriptor(relationDescriptor.TableName, relationDescriptor.FieldDescriptors, newName);
            else if (relationDescriptor.RelationType == RelationType.ForeignKey)
                result = new ForeignKeyDescriptor(relationDescriptor.TableName, relationDescriptor.FieldDescriptors, ((IForeignKeyDescriptor)relationDescriptor).RelatedTableName, ((IForeignKeyDescriptor)relationDescriptor).RelatedFieldDescriptors, newName);
            else
                throw new Exception("Relation type is not supported.");
            return result;
        }

        public static PrimaryKey AddFieldInRelation(PrimaryKey oldRelation, IFieldDescriptor newFieldDescriptor, object newFieldValue)
        {
            IField newF = new Field(newFieldDescriptor, newFieldValue);
            return AddFieldInRelation(oldRelation, newF);
        }

        public static PrimaryKey AddFieldInRelation(PrimaryKey oldRelation, IField newField)
        {
            IDictionary<int, IField> newFields = new Dictionary<int, IField>();
            int order = oldRelation.Fields.Count;
            foreach(KeyValuePair<int, IField> kv in oldRelation.Fields)
                newFields.Add(kv.Key, kv.Value);
            newFields.Add(order, newField);

            return new PrimaryKey(oldRelation.TableName, newFields, oldRelation.Name);
        }

        public static PrimaryKeyDescriptor AddFieldDescInRelationDesc(PrimaryKeyDescriptor oldRelationDescriptor, Type newFieldType, string newFieldName)
        {
            return AddFieldDescInRelationDesc(oldRelationDescriptor, new FieldDescriptor(newFieldType, newFieldName));
        }

        public static PrimaryKeyDescriptor AddFieldDescInRelationDesc(PrimaryKeyDescriptor oldRelationDescriptor, IFieldDescriptor newFieldDescriptor)
        {
            Dictionary<int, IFieldDescriptor> newFieldDescs = new Dictionary<int, IFieldDescriptor>();
            int order = oldRelationDescriptor.FieldDescriptors.Count;
            foreach (KeyValuePair<int, IFieldDescriptor> kv in oldRelationDescriptor.FieldDescriptors)
                newFieldDescs.Add(kv.Key, kv.Value);
            newFieldDescs.Add(order, newFieldDescriptor);

            return new PrimaryKeyDescriptor(oldRelationDescriptor.TableName, newFieldDescs, oldRelationDescriptor.Name);
        }

        public static ForeignKeyDescriptor AddFieldDescInRelationDesc(ForeignKeyDescriptor oldRelationDescriptor, IFieldDescriptor newFieldDescriptor, IFieldDescriptor newRelatedFieldDescriptor)
        {
            IDictionary<int, IFieldDescriptor> newFieldDescs = new Dictionary<int, IFieldDescriptor>();
            foreach(KeyValuePair<int, IFieldDescriptor> kv in oldRelationDescriptor.FieldDescriptors)
                newFieldDescs.Add(kv.Key, kv.Value);
            int order = oldRelationDescriptor.FieldDescriptors.Count;
            newFieldDescs.Add(order, newFieldDescriptor);

            IDictionary<int, IFieldDescriptor> newRelFieldDescs = new Dictionary<int, IFieldDescriptor>();
            foreach (KeyValuePair<int, IFieldDescriptor> kv in oldRelationDescriptor.RelatedFieldDescriptors)
                newRelFieldDescs.Add(kv.Key, kv.Value);
            newRelFieldDescs.Add(order, newRelatedFieldDescriptor);

            return new ForeignKeyDescriptor(oldRelationDescriptor.TableName, newFieldDescs, oldRelationDescriptor.RelatedTableName, newRelFieldDescs, oldRelationDescriptor.Name);
        }
    }

}
